/**
 * WSModules is the class implementing the JSON rendering of the created modules.
 * This is used when invoking the Play! "list-modules" or "install" command line options.
 * 
 * @author Eric LEON
 * @version 1.0.0
 */
package controllers.ws;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.util.List;

import models.Module;
import models.Repository;
import models.Version;
import play.Logger;
import play.i18n.Messages;

import com.google.gson.annotations.Expose;

import controllers.Modules;

public class WSModules extends WSApplication {

	/**
	 * Render all modules of all repositories. 
	 */
	public static void listModules() {
    	ModulesContainer container = new ModulesContainer(Module.list());
    	renderJSONEx(container);
	}

	/**
	 * Render all repositories.
	 */
	public static void listRepositories() {
    	RepositoriesContainer container = new RepositoriesContainer(Repository.list());
    	renderJSONEx(container);
	}
	
	/**
	 * Render all modules for the given repository.
	 * @param name	The repository name.
	 */
	public static void listRepositoryModules(String name) {
		try {
	    	ModulesContainer container = new ModulesContainer(Repository.listModules(name));
	    	renderJSONEx(container);
		} catch (Exception e) {
			Logger.error("cannot render", e);
		}
	}
	
	/**
	 * Sends the module version code to the remote. This is called during the play module
	 * installation.
	 * 
	 * @param name		The module name
	 * @param number	The module version string
	 */
	public static void download(String name, String number) {

		Version ver = null;
		Module mod = null;
		
		try {
			// Find the requested source module
			if ((mod = Module.find("byName", name).first()) == null) {
				// Module not found
				error(Messages.get("ws.modunknown", name));
			}
			// Find the requested module version
			if ((ver = mod.getVersion(number)) == null) {
				// Version doesn't exists
				error(Messages.get("ws.verunknown", number, name));
			}
			// Send the binary content to the requester
			ByteArrayInputStream is = new ByteArrayInputStream(ver.code);
			renderBinary(is);
		} catch (Exception e) {
			error(e);
		}
	}

	/**
	 * Receive a new module from the remote.
	 * 
	 * @param name		The module name
	 * @param number	The module version string
	 * @param archive	The module archive file attachment
	 */
	public static void upload(String name, String number, String matches, File archive) {

		Version ver = null;
		Module mod = null;
		
		try {
			// Find the destination module object
			if ((mod = Module.find("byName", name).first()) == null) {
				// Module not found, must be exists in database first
				error(Messages.get("ws.modunknown", name));
			}
			// See if version not already exists
			if (!number.equals("head") && (mod.getVersion(number) != null)) {
				// Version found, refuse to create the same one
				error(Messages.get("ws.verexists", number, name));
			} 
			Boolean isDefault = number.equals("head")? false: true; 
			// Create a new version instance 
			ver = new Version(number, isDefault, matches, name + "-" + number, null);
			// Retrieve request file content
			if (!Modules.readArchive(ver, archive)) {
				error(Messages.get("module.archive"));
			}
			mod.addVersion(ver);
			// Send request response
			ok();
			return;
    	} catch (Throwable e) {
    		Logger.error("Error reading input stream: %s", e.getMessage());
    		e.printStackTrace();
    	}
	}

	// Class used to simulate the play JSON list-modules behavior: the modules list is embedded into a modules parent
	public static class ModulesContainer {
		
		@Expose
		public List<Module> modules;
		
		public ModulesContainer(List<Module> modules) {
			this.modules = modules;
		}
	}
	
	public static class RepositoriesContainer {
		
		@Expose
		public List<Repository> repositories;
		
		public RepositoriesContainer(List<Repository> repositories) {
			this.repositories = repositories;
		}
	}
}
